home *** CD-ROM | disk | FTP | other *** search
/ MPEG Toolkit / MPEG Toolkit.iso / win / mpg2w11b / mpeg2dec / mpeg2dec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  23.4 KB  |  859 lines

  1. /* mpeg2dec.c, main(), initialization, option processing                    */
  2.  
  3. /* Copyright (C) 1994, MPEG Software Simulation Group. All Rights Reserved. */
  4.  
  5. /*
  6.  * Disclaimer of Warranty
  7.  *
  8.  * These software programs are available to the user without any license fee or
  9.  * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
  10.  * any and all warranties, whether express, implied, or statuary, including any
  11.  * implied warranties or merchantability or of fitness for a particular
  12.  * purpose.  In no event shall the copyright-holder be liable for any
  13.  * incidental, punitive, or consequential damages of any kind whatsoever
  14.  * arising from the use of these programs.
  15.  *
  16.  * This disclaimer of warranty extends to the user of these programs and user's
  17.  * customers, employees, agents, transferees, successors, and assigns.
  18.  *
  19.  * The MPEG Software Simulation Group does not represent or warrant that the
  20.  * programs furnished hereunder are free of infringement of any third-party
  21.  * patents.
  22.  *
  23.  * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
  24.  * are subject to royalty fees to patent holders.  Many of these patents are
  25.  * general enough such that they are unavoidable regardless of implementation
  26.  * design.
  27.  *
  28.  */
  29.  
  30. // MS Windows includes
  31. #include <windows.h>
  32. #include <commdlg.h>
  33. #include <assert.h>
  34. #include <io.h>
  35. #include "gui.h"
  36. #define APPNAME            "Mpeg2Play"    /* The name of this application */
  37. #define BASEWINDOWTITLE    "MPEG2 Software Simulation" /* The title bar text */
  38. #define MAXFILENAME        256           /* maximum length of file pathname      */
  39. #define MAXCUSTFILTER      40            /* maximum size of custom filter buffer */
  40. // display related variables
  41. #define        START        0
  42. #define        READY        1
  43. #define   PLAYING   2
  44. #define   PAUSED    3
  45. #define   FINISH    4
  46. #define        STOP        5
  47.  
  48.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <ctype.h>
  52. #include <fcntl.h>
  53.  
  54. #define GLOBAL
  55. #include "config.h"
  56. #include "global.h"
  57.  
  58. // MS Windows related variables
  59. LRESULT CALLBACK WndProc(HWND   hWnd,       // window handle
  60.                          UINT   message,    // type of message
  61.                          WPARAM uParam,     // additional information
  62.                          LPARAM lParam);    // additional information
  63. static HINSTANCE   hInst;          // current instance
  64. static HWND        ghWnd   =NULL;  // handle to main window
  65. static char       *image   =NULL;
  66. static char        szFileName[MAXFILENAME]="";
  67. static unsigned short gusState = START;
  68. static int         nDitherType;
  69. static HDC         hDC;
  70. static HPALETTE    hpal,
  71.                    hPalPrev=NULL;
  72. static PBITMAPINFO pbmi    =NULL;
  73.  
  74. static void play_movie(void);
  75. extern int         __argc;
  76. extern char      **__argv;
  77.  
  78. /* private prototypes */
  79. static void initdecoder _ANSI_ARGS_((void));
  80. static void options _ANSI_ARGS_((int *argcp, char **argvp[]));
  81. static int getval _ANSI_ARGS_((char *argv[]));
  82.  
  83.  
  84. // MS Windows related functions
  85. /////////////////////////////////////////////////////////////////////////////
  86. /*
  87.  *********************************************************************************
  88.  *
  89.  * WinMain:
  90.  *
  91.  *********************************************************************************
  92. */
  93.  
  94. //
  95. // yield function to simulate multitasking on MS Windows
  96. //
  97. static void myYield(void)
  98. {
  99.     MSG        msg;
  100.  
  101.     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  102.     {
  103.         TranslateMessage(&msg);// Translates virtual key codes
  104.         DispatchMessage(&msg); // Dispatches message to window
  105.     }
  106. }
  107.  
  108. //
  109. // initializations
  110. //
  111. static BOOL InitApplication(HINSTANCE hInstance)
  112. {
  113.    WNDCLASS  wc;
  114.  
  115.    // Fill in window class structure with parameters that describe the
  116.    // main window.
  117.  
  118.    wc.style         = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// Class style(s).
  119.    wc.lpfnWndProc   = (WNDPROC)WndProc;           // Window Procedure
  120.    wc.cbClsExtra    = 0;                          // No per-class extra data.
  121.    wc.cbWndExtra    = 0;                          // No per-window extra data.
  122.    wc.hInstance     = hInstance;                  // Owner of this class
  123.    wc.hIcon         = LoadIcon (hInstance, APPNAME); // Icon name from .RC
  124.    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);// Cursor
  125.    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);   // Default color
  126.    wc.lpszMenuName  = APPNAME;                    // Menu name from .RC
  127.    wc.lpszClassName = APPNAME;                    // Name to register as
  128.  
  129.    // Register the window class and return success/failure code.
  130.    return (RegisterClass(&wc));
  131. }
  132.  
  133. static BOOL InitInstance(HINSTANCE hInstance,int       nCmdShow)
  134. {
  135.  
  136.     // Save the instance handle in static variable, which will be used in
  137.     // many subsequence calls from this application to Windows.
  138.  
  139.     hInst = hInstance; // Store instance handle in our global variable
  140.  
  141.     // Create a main window for this application instance.
  142.  
  143.     ghWnd = CreateWindow(APPNAME,            // See RegisterClass() call.
  144.                          BASEWINDOWTITLE,    // Text for window title bar.
  145.                          WS_OVERLAPPEDWINDOW &
  146.                          ~WS_THICKFRAME &
  147.                          ~WS_MAXIMIZEBOX,    // Window style.
  148.                          CW_USEDEFAULT,
  149.                          0,
  150.                          CW_USEDEFAULT,
  151.                          0,                  // Use default positioning
  152.                          NULL,               // Overlapped windows have no parent.
  153.                          NULL,               // Use the window class menu.
  154.                          hInstance,          // This instance owns this window.
  155.                          NULL                // We don't use any data in our WM_CREATE
  156.         );
  157.  
  158.     // If window could not be created, return "failure"
  159.     if (!ghWnd)
  160.        return (FALSE);
  161.  
  162.     // Make the window visible; update its client area; and return "success"
  163.     ShowWindow(ghWnd, nCmdShow); // Show the window
  164.     UpdateWindow(ghWnd);         // Sends WM_PAINT message
  165.  
  166.     return (TRUE);              // We succeeded...
  167.  
  168. }
  169.  
  170. //
  171. // prompts the user for the efile name
  172. //
  173. static BOOL AskUserFileName(char szFileName[],char szFileTitle[])
  174. {
  175.    /* new variables for common dialogs */
  176.    static char         szFilterSpec[]="MPEG2 Video Files\0*.M2V\0MPEG1 Video Files\0*.M1V\0MPEG Files\0*.MPG\0All Files (*.*)\0*.*\0";
  177.    static char         szInitialDirectory[MAXFILENAME]="";
  178.           OPENFILENAME ofn;
  179.  
  180.    memset(&ofn,0,sizeof(ofn));
  181.  
  182.    /* fill in non-variant fields of OPENFILENAME struct. */
  183.    ofn.lStructSize       = sizeof(OPENFILENAME);
  184.    ofn.hwndOwner         = ghWnd;
  185.    ofn.lpstrFilter       = szFilterSpec;
  186.    ofn.lpstrCustomFilter = NULL;
  187.    ofn.nMaxCustFilter    = 0;
  188.    ofn.nFilterIndex      = 0;
  189.    ofn.lpstrFile         = szFileName;
  190.    ofn.nMaxFile          = MAXFILENAME;
  191.    if (!szInitialDirectory[0])
  192.       GetModuleFileName(hInst, szInitialDirectory, MAXFILENAME);
  193.  
  194.    // strip the file name
  195.    *(LPSTR)strrchr(szInitialDirectory,'\\')=0;
  196.  
  197.    ofn.lpstrInitialDir     = szInitialDirectory;
  198.    ofn.lpstrFileTitle      = szFileTitle;
  199.    ofn.nMaxFileTitle       = MAXFILENAME;
  200.    ofn.lpstrTitle          = NULL;
  201.    ofn.lpstrDefExt         = "MPG";
  202.    ofn.Flags               = 0;
  203.  
  204.    if (!GetOpenFileName ((LPOPENFILENAME)&ofn))
  205.       return FALSE;
  206.  
  207.    // save the current directory
  208.    lstrcpy(szInitialDirectory,szFileName);
  209.    return TRUE;
  210. }
  211.  
  212.  
  213. /*********************************************************************************
  214.  *
  215.  * About box
  216.  *
  217. *********************************************************************************
  218. */
  219.  
  220. BOOL CALLBACK About(HWND   hDlg,         // window handle of the dialog box
  221.                     UINT   message,      // type of message
  222.                     WPARAM uParam,       // message-specific information
  223.                     LPARAM lParam)
  224. {
  225.    switch (message)
  226.    {
  227.       case WM_COMMAND:                     // message: received a command
  228.          if (LOWORD(uParam) == IDOK || LOWORD(uParam) == IDCANCEL)
  229.          {
  230.             EndDialog(hDlg, TRUE);        // Exit the dialog
  231.             return (TRUE);
  232.          }
  233.          break;
  234.    }
  235.    return (FALSE); // Didn't process the message
  236.  
  237.    lParam; // This will prevent 'unused formal parameter' warnings
  238. }
  239.  
  240. //
  241. // Main window procedure
  242. //
  243. LRESULT CALLBACK WndProc(HWND   hWnd,       // window handle
  244.                          UINT   message,    // type of message
  245.                          WPARAM uParam,     // additional information
  246.                          LPARAM lParam)     // additional information
  247. {
  248.    switch (message)
  249.    {
  250.       case WM_CLOSE:
  251.         gusState = STOP;
  252.         myYield();
  253.       return (DefWindowProc(hWnd, message, uParam, lParam));
  254.         break;
  255.  
  256.  
  257.       case WM_DESTROY:  // message: window being destroyed
  258.         gusState = STOP;
  259.         myYield();
  260.       PostQuitMessage(0);
  261.       break;
  262.  
  263.       case WM_COMMAND:  // message: command from application menu
  264.       {
  265.         int wmId, wmEvent;
  266.  
  267.         wmId    = LOWORD(uParam);
  268.         wmEvent = HIWORD(uParam);
  269.  
  270.         switch (wmId)
  271.         {
  272.            case IDM_OPEN:
  273.            {
  274.               char szWindowTitle[80];
  275.               char szFileTitle[MAXFILENAME];
  276.  
  277.                // if something was playing, give a chance to stop.
  278.               if (gusState > READY)
  279.               {
  280.                  gusState = STOP;
  281.                  myYield();
  282.               }
  283.  
  284.               EnableMenuItem(GetMenu(hWnd), IDM_PLAY, MF_GRAYED | MF_DISABLED);
  285.  
  286.               szFileName[0]=0;
  287.               if (!AskUserFileName (szFileName,szFileTitle))
  288.                  return FALSE;
  289.  
  290.               lstrcpy(szWindowTitle, BASEWINDOWTITLE);
  291.               lstrcat(szWindowTitle, " - ");
  292.               lstrcat(szWindowTitle, szFileTitle);
  293.               SetWindowText(hWnd, szFileTitle);
  294.  
  295.               // enable play menu
  296.               EnableMenuItem(GetMenu(hWnd), IDM_PLAY, MF_ENABLED);
  297.  
  298.               gusState = READY;
  299.               break;
  300.            }
  301.  
  302.            case IDM_PLAY:
  303.               // disable play menu while playing
  304.               EnableMenuItem(GetMenu(hWnd), IDM_STOP, MF_ENABLED);
  305.               EnableMenuItem(GetMenu(hWnd), IDM_PLAY, MF_GRAYED | MF_DISABLED);
  306.  
  307.               // play the movie. It returns after the playing ended
  308.               play_movie();
  309.  
  310.               // disable stop menu
  311.               EnableMenuItem(GetMenu(hWnd), IDM_STOP, MF_GRAYED | MF_DISABLED);
  312.               EnableMenuItem(GetMenu(hWnd), IDM_PLAY, MF_ENABLED);
  313.               SetWindowText(hWnd, BASEWINDOWTITLE);
  314.               break;
  315.  
  316.            case IDM_STOP:
  317.               gusState=STOP;
  318.               // force a task switch to allow the decoder to see the stop command
  319.               myYield();
  320.               break;
  321.  
  322.            case IDM_EXIT:
  323.               SendMessage(hWnd, WM_CLOSE, 0, 0l);
  324.               break;
  325.  
  326.            case IDM_ABOUT:
  327.            {
  328.               FARPROC lpProcAbout;  // pointer to the "About" function
  329.  
  330.               lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
  331.               DialogBox(hInst,                 // current instance
  332.                         "AboutBox",            // dlg resource to use
  333.                         hWnd,                  // parent handle
  334.                         (DLGPROC)lpProcAbout); // About() instance address
  335.  
  336.               FreeProcInstance(lpProcAbout);
  337.               break;
  338.            }
  339.  
  340.            case IDM_YUV_FILE:
  341.            case IDM_Y_U_V_FILE:
  342.            case IDM_TGA_FILE:
  343.            case IDM_DISPLAY8:
  344.            case IDM_DISPLAY24:
  345.               // reset the display.
  346.               // It will be reinitialized the first time it will be called
  347.               switch (outtype)
  348.               {
  349.                  case T_YUV:
  350.                    CheckMenuItem(GetMenu(hWnd), IDM_YUV_FILE, MF_UNCHECKED);
  351.                    break;
  352.  
  353.                  case T_SIF:
  354.                    CheckMenuItem(GetMenu(hWnd), IDM_Y_U_V_FILE, MF_UNCHECKED);
  355.                    break;
  356.  
  357.                  case T_TGA:
  358.                    CheckMenuItem(GetMenu(hWnd), IDM_TGA_FILE, MF_UNCHECKED);
  359.                    break;
  360.  
  361. #ifdef DISPLAY
  362.                  case T_X11:
  363.                    if (nDitherType==8)
  364.                       CheckMenuItem(GetMenu(hWnd), IDM_DISPLAY8, MF_UNCHECKED);
  365.                    else
  366.                       CheckMenuItem(GetMenu(hWnd), IDM_DISPLAY24, MF_UNCHECKED);
  367.                    break;
  368. #endif
  369.               }
  370.               switch (wmId)
  371.               {
  372.                  case IDM_YUV_FILE:
  373.                     CheckMenuItem(GetMenu(hWnd), IDM_YUV_FILE, MF_CHECKED);
  374.                     outtype=T_YUV;
  375.                     break;
  376.  
  377.                  case IDM_Y_U_V_FILE:
  378.                     CheckMenuItem(GetMenu(hWnd), IDM_Y_U_V_FILE, MF_CHECKED);
  379.                     outtype=T_SIF;
  380.                     break;
  381.  
  382.                  case IDM_TGA_FILE:
  383.                     CheckMenuItem(GetMenu(hWnd), IDM_TGA_FILE, MF_CHECKED);
  384.                     outtype=T_TGA;
  385.                     break;
  386.  
  387. #ifdef DISPLAY
  388.                  case IDM_DISPLAY8:
  389.                     CheckMenuItem(GetMenu(hWnd), IDM_DISPLAY8, MF_CHECKED);
  390.                     outtype=T_X11;
  391.                     nDitherType=8;
  392.                     break;
  393.  
  394.                  case IDM_DISPLAY24:
  395.                     CheckMenuItem(GetMenu(hWnd), IDM_DISPLAY24, MF_CHECKED);
  396.                     outtype=T_X11;
  397.                     nDitherType=24;
  398.                     break;
  399. #endif
  400.               }
  401.         }
  402.         break;
  403.       }
  404.  
  405.       default:          // Passes it on if unproccessed
  406.         return (DefWindowProc(hWnd, message, uParam, lParam));
  407.    }
  408.    return (0);
  409. }
  410.  
  411. //
  412. // program entry point
  413. //
  414. int APIENTRY WinMain(HINSTANCE   hInstance,
  415.                      HINSTANCE   hPrevInstance,
  416.                      LPSTR       lpCmdLine,
  417.                      int         nCmdShow)
  418. {
  419.     MSG msg;
  420.  
  421.     if (!hPrevInstance)
  422.        // Other instances of app running?
  423.         if (!InitApplication(hInstance))
  424.            // Initialize shared things
  425.            return (FALSE);     // Exits if unable to initialize
  426.  
  427.     /* Perform initializations that apply to a specific instance */
  428.     if (!InitInstance(hInstance, nCmdShow))
  429.        return (FALSE);
  430.  
  431.  
  432.     // start-up initialization
  433.     verbose = 0;
  434. #ifdef DISPLAY
  435.     outtype = T_X11;
  436.     hDC     = GetDC(ghWnd);
  437.     if (GetDeviceCaps(hDC,BITSPIXEL)>=24)
  438.     {
  439.        CheckMenuItem(GetMenu(ghWnd), IDM_DISPLAY24, MF_CHECKED);
  440.        nDitherType=24;
  441.     }
  442.     else
  443.     {
  444.        CheckMenuItem(GetMenu(ghWnd), IDM_DISPLAY8, MF_CHECKED);
  445.        nDitherType=8;
  446.     }
  447. #else
  448.     outtype=T_YUV;
  449.     CheckMenuItem(GetMenu(ghWnd), IDM_YUV_FILE, MF_CHECKED);
  450. #endif
  451.     framestoreflag = 1;
  452.     sflag = 0;
  453.     refidct = 0;
  454.     ld = &base; /* select base layer context */
  455.  
  456.     options(&__argc,&__argv);
  457.  
  458. #ifdef DISPLAY
  459.     if (outtype==T_X11)
  460.        outputname = "";
  461.     else
  462. #endif
  463.        outputname="rec%d";
  464.  
  465.     /* Acquire and dispatch messages until a WM_QUIT message is received. */
  466.     while (GetMessage(&msg, // message structure
  467.                       NULL,   // handle of window receiving the message
  468.                       0,      // lowest message to examine
  469.                       0))     // highest message to examine
  470.     {
  471.         TranslateMessage(&msg);// Translates virtual key codes
  472.         DispatchMessage(&msg); // Dispatches message to window
  473.     }
  474.  
  475.     return (msg.wParam); // Returns the value from PostQuitMessage
  476.  
  477.     lpCmdLine; // This will prevent 'unused formal parameter' warnings
  478. }
  479.  
  480. #ifdef DISPLAY
  481. //
  482. // display initialization
  483. //
  484. extern int convmat[8][4]; // defined in display.c
  485.  
  486. static void init_display(void)
  487. {
  488.   pbmi    = (PBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + 240 * sizeof(RGBQUAD));
  489.   pbmi->bmiHeader.biSize = (LONG)sizeof(BITMAPINFOHEADER);
  490.   pbmi->bmiHeader.biPlanes = 1;
  491.   pbmi->bmiHeader.biCompression = 0l;
  492.   pbmi->bmiHeader.biSizeImage = 0l;
  493.   pbmi->bmiHeader.biXPelsPerMeter = 0l;
  494.   pbmi->bmiHeader.biYPelsPerMeter = 0l;
  495.   pbmi->bmiHeader.biClrUsed = 240;
  496.   pbmi->bmiHeader.biClrImportant = 240;
  497.   pbmi->bmiHeader.biBitCount = nDitherType;
  498.   pbmi->bmiHeader.biWidth = coded_picture_width ;
  499.   pbmi->bmiHeader.biHeight= coded_picture_height;
  500.   if ( pbmi->bmiHeader.biBitCount==8 )
  501.   {
  502.      // for 8 BPP, build the color palette
  503.  
  504.      LOGPALETTE *plgpl;
  505.      short      *pPalIndex;
  506.      int         crv, cbu, cgu, cgv;
  507.      int         y, u, v;
  508.      int         i;
  509.  
  510.      plgpl = (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + 240 * sizeof(PALETTEENTRY));
  511.      plgpl->palNumEntries = 240;
  512.      plgpl->palVersion = 0x300;
  513.      pPalIndex=(short *)pbmi->bmiColors;
  514.  
  515.      /* matrix coefficients */
  516.      crv = convmat[matrix_coefficients][0];
  517.      cbu = convmat[matrix_coefficients][1];
  518.      cgu = convmat[matrix_coefficients][2];
  519.      cgv = convmat[matrix_coefficients][3];
  520.  
  521.      for (i=16; i<240; i++)
  522.      {
  523.        /* color space conversion */
  524.        y = 16*((i>>4)&15) + 8;
  525.        u = 32*((i>>2)&3)  - 48;
  526.        v = 32*(i&3)       - 48;
  527.  
  528.        y = 76309 * (y - 16); /* (255/219)*65536 */
  529.  
  530.        plgpl->palPalEntry[i].peRed   = clp[(y + crv*v + 32768)>>16];
  531.        plgpl->palPalEntry[i].peGreen = clp[(y - cgu*u -cgv*v + 32768)>>16];
  532.        plgpl->palPalEntry[i].peBlue  = clp[(y + cbu*u + 32786)>>16];
  533.        pPalIndex[i]=i;
  534.      }
  535.      hpal = CreatePalette(plgpl);
  536.      free(plgpl);
  537.      hPalPrev=SelectPalette(hDC,hpal,FALSE);
  538.      RealizePalette(hDC);
  539.   }
  540. }
  541.  
  542. //
  543. // display clean-up
  544. //
  545. static void exit_display()
  546. {
  547.    if (pbmi)
  548.    {
  549.       free(pbmi);
  550.       pbmi=NULL;
  551.    }
  552.    if (hPalPrev)
  553.    {
  554.        SelectPalette(hDC,hPalPrev,FALSE);
  555.        DeleteObject(hpal);
  556.        hPalPrev=NULL;
  557.    }
  558. }
  559.  
  560. //
  561. // display the image on the MS Windows screen
  562. //
  563. void display_image(dithered_image)
  564. unsigned char *dithered_image;
  565. {
  566.   /* display dithered image */
  567.   SetDIBitsToDevice(hDC,0,0,coded_picture_width,coded_picture_height,
  568.                      0,0,0,coded_picture_height,dithered_image,pbmi,DIB_PAL_COLORS);
  569. }
  570. #endif
  571.  
  572.  
  573. //
  574. // decode a file and store and/or display it
  575. //
  576. static void play_movie(void)
  577. {
  578.   int framenum;
  579.  
  580.   /* open MPEG input file(s) */
  581.   if ((base.infile=open(szFileName,O_RDONLY|O_BINARY))<0)
  582.   {
  583.     sprintf(errortext,"Input file %s not found\n",szFileName);
  584.     error(errortext);
  585.   }
  586.  
  587.   initbits();
  588.  
  589.   if (getheader())
  590.   {
  591.     RECT wr,cr;
  592.     int  d;
  593.  
  594.     // size window to film size
  595.     SetRect(&cr,0,0,horizontal_size,vertical_size);
  596.     wr=cr;
  597.     AdjustWindowRect(&wr,GetWindowLong(ghWnd,GWL_STYLE),TRUE);
  598.     OffsetRect(&wr,-wr.left,-wr.top);
  599.     SetWindowPos(ghWnd,HWND_TOP,0,0,wr.right,wr.bottom,SWP_NOMOVE);
  600.  
  601.     // for QSIF movies the menu will wrap around so we need
  602.     // to increase the height of the window
  603.     GetClientRect(ghWnd, &wr);
  604.     d=cr.bottom-(wr.bottom-wr.top);
  605.     if (d>0)
  606.     {
  607.        GetWindowRect(ghWnd, &wr);
  608.        SetWindowPos(ghWnd,HWND_TOP,0,0,wr.right-wr.left,wr.bottom-wr.top+d,SWP_NOMOVE);
  609.     }
  610.  
  611.     initdecoder();
  612.  
  613.     if (outtype==T_X11)
  614.     {
  615.       init_dither(nDitherType);
  616.       init_display();
  617.     }
  618.  
  619.     framenum = 0;
  620.  
  621.     do
  622.     {
  623.       getpicture(framenum);
  624.  
  625.       if (!secondfield)
  626.          framenum++;
  627.  
  628.       // give the user a chance to perform something
  629.       myYield();
  630.       if (gusState==STOP)
  631.          break;
  632.     }
  633.     while (getheader());
  634.  
  635.     if (framenum!=0)
  636.     {
  637.       /* put last frame */
  638.       putlast(framenum);
  639.     }
  640.  
  641.     if (outtype==T_X11)
  642.       exit_display();
  643.   }
  644.  
  645.   close(base.infile);
  646. }
  647.  
  648. /////////////////////////////////////////////////////////////////////
  649. //
  650. // MPEG related functions
  651. //
  652. // (portable)
  653. //
  654. static void initdecoder()
  655. {
  656.   int i, cc, size;
  657.   static int blk_cnt_tab[3] = {6,8,12};
  658.  
  659.   /* check scalability mode of enhancement layer */
  660.   if (twostreams && enhan.scalable_mode!=SC_SNR &&
  661.      !(base.scalable_mode==SC_DP && base.scalable_mode==SC_DP))
  662.     error("unsupported scalability mode\n");
  663.  
  664.   /* clip table */
  665.   if (!(clp=(unsigned char *)malloc(1024)))
  666.     error("malloc failed\n");
  667.  
  668.   clp += 384;
  669.  
  670.   for (i=-384; i<640; i++)
  671.     clp[i] = (i<0) ? 0 : ((i>255) ? 255 : i);
  672.  
  673.   /* force MPEG-1 parameters */
  674.   if (!base.mpeg2)
  675.   {
  676.     prog_seq = 1;
  677.     prog_frame = 1;
  678.     pict_struct = FRAME_PICTURE;
  679.     frame_pred_dct = 1;
  680.     chroma_format = CHROMA420;
  681.     matrix_coefficients = 5;
  682.   }
  683.  
  684.   /* round to nearest multiple of coded macroblocks */
  685.   mb_width = (horizontal_size+15)/16;
  686.   mb_height = (base.mpeg2 && !prog_seq) ? 2*((vertical_size+31)/32)
  687.                                         : (vertical_size+15)/16;
  688.   coded_picture_width = 16*mb_width;
  689.   coded_picture_height = 16*mb_height;
  690.  
  691.   chrom_width = (chroma_format==CHROMA444) ? coded_picture_width
  692.                                            : coded_picture_width>>1;
  693.   chrom_height = (chroma_format!=CHROMA420) ? coded_picture_height
  694.                                             : coded_picture_height>>1;
  695.   blk_cnt = blk_cnt_tab[chroma_format-1];
  696.  
  697.   for (cc=0; cc<3; cc++)
  698.   {
  699.     if (cc==0)
  700.       size = coded_picture_width*coded_picture_height;
  701.     else
  702.       size = chrom_width*chrom_height;
  703.  
  704.     if (!(refframe[cc] = (unsigned char *)malloc(size)))
  705.       error("malloc failed\n");
  706.  
  707.     if (!(oldrefframe[cc] = (unsigned char *)malloc(size)))
  708.       error("malloc failed\n");
  709.  
  710.     if (!(auxframe[cc] = (unsigned char *)malloc(size)))
  711.       error("malloc failed\n");
  712.  
  713.     if (base.scalable_mode==SC_SPAT)
  714.     {
  715.       /* this assumes lower layer is 4:2:0 */
  716.       if (!(llframe0[cc] = (unsigned char *)malloc((llw*llh)/(cc?4:1))))
  717.         error("malloc failed\n");
  718.       if (!(llframe1[cc] = (unsigned char *)malloc((llw*llh)/(cc?4:1))))
  719.         error("malloc failed\n");
  720.     }
  721.   }
  722.  
  723.   if (base.scalable_mode==SC_SPAT)
  724.   {
  725.     if (!(lltmp = (short *)malloc(llw*((llh*vn)/vm)*sizeof(short))))
  726.       error("malloc failed\n");
  727.   }
  728.  
  729.   /* IDCT */
  730.   if (refidct)
  731.     init_idctref();
  732.   else
  733.     init_idct();
  734. }
  735.  
  736. void error(text)
  737. char *text;
  738. {
  739.   fprintf(stderr,text);
  740.   exit(1);
  741. }
  742.  
  743. /* compliance warning messages to user, but don't exit() */
  744. void warning(text)
  745. char *text;
  746. {
  747.   if (!quiet)
  748.   {
  749.     fprintf(stderr,"%s\n",text);
  750.   }
  751. }
  752.  
  753. /* trace output */
  754. void printbits(code,bits,len)
  755. int code,bits,len;
  756. {
  757.   int i;
  758.   for (i=0; i<len; i++)
  759.     printf("%d",(code>>(bits-1-i))&1);
  760. }
  761.  
  762. /* option processing */
  763. static void options(argcp,argvp)
  764. int *argcp;
  765. char **argvp[];
  766. {
  767.   while (*argcp>1 && (*argvp)[1][0]=='-')
  768.   {
  769.     while ((*argvp)[1][1])
  770.     {
  771.       switch (toupper((*argvp)[1][1]))
  772.       {
  773.       case 'V':
  774.         verbose = getval(*argvp);
  775.         break;
  776.       case 'O':
  777.         outtype = getval(*argvp);
  778. #ifdef DISPLAY
  779.         if (outtype==T_X11HIQ)
  780.         {
  781.           hiQdither = 1;
  782.           outtype=T_X11;
  783.         }
  784. #endif
  785.         break;
  786.       case 'F':
  787.         framestoreflag = 1;
  788.         break;
  789.       case 'S':
  790.         sflag = 1;
  791.         break;
  792.       case 'R':
  793.         refidct = 1;
  794.         break;
  795.       case 'T':
  796.         trace = 1;
  797.         break;
  798.       case 'Q':
  799.         quiet = 1;
  800.         break;
  801.       default:
  802.         fprintf(stderr,"undefined option -%c ignored\n",(*argvp)[1][1]);
  803.       }
  804.  
  805.       (*argvp)[1]++;
  806.     }
  807.  
  808.     (*argvp)++;
  809.     (*argcp)--;
  810.   }
  811.  
  812.   if (sflag)
  813.   {
  814.     /* input file for spatial prediction */
  815.     llinputname = (*argvp)[1];
  816.     (*argvp)++;
  817.     (*argcp)--;
  818.   }
  819.  
  820. #ifdef DISPLAY
  821.   if (outtype==T_X11)
  822.   {
  823.     framestoreflag = 1; /* two avoid calling dither() twice */
  824.     (*argcp)++; /* fake outfile parameter */
  825.   }
  826. #endif
  827.  
  828. #if 0
  829.   if (*argcp!=3 && *argcp!=4)
  830.   {
  831.     printf("\n%s, %s\n",version,author);
  832.     printf("Usage:   mpeg2decode {options} input.m2v {upper.m2v} {outfile}\n\
  833. Options: -vn  verbose output (n: level)\n\
  834.          -on  output format (0: YUV, 1: SIF, 2: TGA, 3:PPM, 4:X11, 5:X11 HiQ)\n\
  835.          -f   store interlaced video in frame format\n\
  836.          -q   disable warnings to stderr\n\
  837.          -r   use double precision reference IDCT\n\
  838.          -s infile  spatial scalable sequence\n\
  839.          -t   enable low level tracing\n");
  840.     exit(0);
  841.   }
  842. #endif
  843. }
  844.  
  845. static int getval(argv)
  846. char *argv[];
  847. {
  848.   int val;
  849.  
  850.   if (sscanf(argv[1]+2,"%d",&val)!=1)
  851.     return 0;
  852.  
  853.   while (isdigit(argv[1][2]))
  854.     argv[1]++;
  855.  
  856.   return val;
  857. }
  858.  
  859.